#pragma once

#include <array>
#include <glm/glm.hpp>

#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/hash.hpp>

struct Vertex
{
    glm::vec3 position;
    glm::vec3 color;
    glm::vec2 texCoord;

    static VkVertexInputBindingDescription getBindingDescription()
    {
        //指定数据条目之间的间隔字节数以及是否每个顶点之后或者每个instance之后移动到下一个条目
        VkVertexInputBindingDescription bindingDescription = { };
        bindingDescription.binding = 0;                                                 //指定数组中对应的绑定索引
        bindingDescription.stride = sizeof(Vertex);                                     //指定一个条目到下一个条目的字节数
        // VK_VERTEX_INPUT_RATE_VERTEX: 移动到每个顶点后的下一个数据条目
        // VK_VERTEX_INPUT_RATE_INSTANCE: 在每个instance之后移动到下一个数据条目
        bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
        return bindingDescription;
    }

    static std::array<VkVertexInputAttributeDescription, 3> getAttributeDescriptions()
    {
        //一个属性描述结构体最终描述了顶点属性如何从对应的绑定描述过的顶点数据来解析数据。我们有两个属性，position和color，所以我们需要两个属性描述结构体
        std::array<VkVertexInputAttributeDescription, 3> attributeDescriptions = { };
        attributeDescriptions[0].binding = 0;                                           //告诉Vulkan每个顶点数据的来源
        attributeDescriptions[0].location = 0;                                          //引用了vertex shader作为输入的location指令
        attributeDescriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT;
        attributeDescriptions[0].offset = offsetof(Vertex, position);

        attributeDescriptions[1].binding = 0;
        attributeDescriptions[1].location = 1;
        attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;
        attributeDescriptions[1].offset = offsetof(Vertex, color);

        attributeDescriptions[2].binding = 0;
        attributeDescriptions[2].location = 2;
        attributeDescriptions[2].format = VK_FORMAT_R32G32_SFLOAT;
        attributeDescriptions[2].offset = offsetof(Vertex, texCoord);
        
        return attributeDescriptions;
    }

    bool operator==(const Vertex& other) const
    {
        return position == other.position && color == other.color && texCoord == other.texCoord;
    }
};

namespace std
{
    template<> struct hash<Vertex>
    {
        size_t operator()(Vertex const& vertex) const
        {
            return ((hash<glm::vec3>()(vertex.position) ^
                   (hash<glm::vec3>()(vertex.color) << 1)) >> 1) ^
                   (hash<glm::vec2>()(vertex.texCoord) << 1);
        }
    };
}


struct UniformBufferObject
{
    glm::mat4 model;
    glm::mat4 view;
    glm::mat4 proj;
};
